﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Cfg;
using NHibernate;
using NHibernate.Context;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using System.Reflection;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Inspections;

namespace Infra.NHibernateFramework {
    public class EnumConvention : IPropertyConvention, IPropertyConventionAcceptance {
        #region IPropertyConvention Members

        public void Apply(IPropertyInstance instance) {
            instance.CustomType(instance.Property.PropertyType);
        }

        #endregion

        #region IPropertyConventionAcceptance Members

        public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) {
            criteria.Expect(x => x.Property.PropertyType.IsEnum);
        }

        #endregion
    }

    public class TableNameConvention : IClassConvention {
        public void Apply(IClassInstance instance) {
            instance.Table("tbl_" + instance.EntityType.Name);
        }
    }

    public static class NHibernateHelper {
        private static ISessionFactory _sessionFactory;
        private static object syncRoot = new Object();

        public static ISessionFactory SessionFactory {
            get {
                if (_sessionFactory == null) {
                    lock (syncRoot) {
                        if (_sessionFactory == null) {
                            _sessionFactory = Fluently.Configure()
                                                      .Database(MsSqlConfiguration.MsSql2008
                                                                                  .ConnectionString(c => c.FromConnectionStringWithKey("Financeiro"))
                                                                                  .ShowSql())
                                                      .Mappings(m => m.FluentMappings
                                                                      .AddFromAssembly(Assembly.GetExecutingAssembly())
                                                                      .Conventions.AddFromAssemblyOf<EnumConvention>()
                                                                      .Conventions.AddFromAssemblyOf <TableNameConvention>())
                                                      .ExposeConfiguration(c => c.SetProperty("current_session_context_class", "web"))
                                                      .Cache(c => c.UseQueryCache().UseSecondLevelCache().ProviderClass<NHibernate.Caches.SysCache2.SysCacheProvider>())
                                //.ExposeConfiguration(BuildSchema)
                                                      .BuildSessionFactory();
                        }
                    }
                }
                return _sessionFactory;
            }
        }

        /******* NÃO UTILIZAR EM PRODUÇÃO *****/
        private static void BuildSchema(Configuration config) {
            SchemaExport schema = new SchemaExport(config);
            schema.Drop(false, true);
            schema.Create(false, true);
        }

        public static ISession GetCurrentSession() {
            if (!CurrentSessionContext.HasBind(SessionFactory)) {
                CurrentSessionContext.Bind(SessionFactory.OpenSession());
            }
            return SessionFactory.GetCurrentSession();
        }

        public static void DisposeSession() {
            var session = GetCurrentSession();
            session.Close();
            session.Dispose();
        }

        public static void BeginTransaction() {
            GetCurrentSession().BeginTransaction();
        }

        public static void CommitTransaction() {
            var session = GetCurrentSession();
            if (session.Transaction.IsActive)
                session.Transaction.Commit();
        }

        public static void RollbackTransaction() {
            var session = GetCurrentSession();
            if (session.Transaction.IsActive)
                session.Transaction.Rollback();
        }

        //public delegate void CodeExecute();

        //public static void ExecuteTransaction(CodeExecute codeExecute) {
        //    using (var transacao = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 1, 0))) {
        //        using (var transaction = NHibernateHelper.GetCurrentSession().BeginTransaction()) {
        //            try {
        //                codeExecute();

        //                transaction.Commit();
        //            } catch (Exception ex) {

        //                if (transaction.IsActive)
        //                    transaction.Rollback();
        //                throw;
        //            }
        //        }

        //        transacao.Complete();
        //    }
        //}
    }
}
